/**
 * 表单插件，依赖于jquery.validation插件
 */
(function ($) {
    /**
     * submit the form
     */
    function ajaxSubmit(target, options) {
        var opts = $.data(target, 'form').options;
        $.extend(opts, options || {});

        var param = $.extend({}, opts.queryParams, options.queryParams);
        if (opts.onSubmit.call(target, param) == false) {
            return;
        }
        App.blockUI({
            boxed: true,
            message: "处理中..."
        });
        $(target).find(".form-control").attr("disable", "disable");
        var formData = null;
        if (opts.multipart) {
            formData = new FormData($(target)[0]);
            for (var name in param) {
                formData.append(name, param[name]);
            }
        } else {
            formData = $(target).serializeArray();
            for (var name in param) {
                var value = param[name];
                formData.push({'name': name,'value':value});
            }
        }
        if(opts.contentType){
            opts.headers = (opts.headers == null)?{}:opts.headers;
            opts.headers['content-type'] = opts.contentType;
            if(opts.contentType.indexOf('application/json') != -1){
                var data = {};
                for(var i = 0; i < formData.length;i++){
                    data[formData[i].name] = formData[i].value;
                }
                formData = JSON.stringify(data);
            }
        }
        App.post(opts.url, formData, function (result) {
            App.unblockUI();
            opts.success(result);
        }, function (error, obj) {
            App.unblockUI();
            $(target).find(".form-control").removeAttr("disable");
            if (typeof opts.error == 'function') {
                opts.error(error, obj);
            }
        }, opts.multipart,opts.contentType,opts.headers);
    }

    /**
     * load form data
     * if data is a URL string type load from remote site,
     * otherwise load from local data object.
     */
    function load(target, data) {
        var opts = $.data(target, 'form').options;

        if (typeof data == 'string') {
            var param = {};
            if (opts.onBeforeLoad.call(target, param) == false) return;

            $.ajax({
                url: data,
                data: param,
                dataType: 'json',
                processData:opts.multipart,
                contentType:opts.contentType,
                headers:opts.headers,
                success: function (data) {
                    _load(data);
                },
                error: function () {
                    opts.onLoadError.apply(target, arguments);
                }
            });
        } else {
            _load(data);
        }

        function _load(data) {
            var form = $(target);
            for (var name in data) {
                var val = data[name];
                if (!_checkField(name, val)) {
                    if (!_loadBox(name, val)) {
                        form.find('input[name="' + name + '"]').val(val);
                        form.find('textarea[name="' + name + '"]').val(val);
                        form.find('select[name="' + name + '"]').val(val);
                    }
                }
            }
            opts.onLoadSuccess.call(target, data);
            form.form('validate');
        }

        /**
         * check the checkbox and radio fields
         */
        function _checkField(name, val) {
            var cc = $(target).find('[switchbuttonName="' + name + '"]');
            if (cc.length) {
                cc.switchbutton('uncheck');
                cc.each(function () {
                    if (_isChecked($(this).switchbutton('options').value, val)) {
                        $(this).switchbutton('check');
                    }
                });
                return true;
            }
            cc = $(target).find('input[name="' + name + '"][type=radio], input[name="' + name + '"][type=checkbox]');
            if (cc.length) {
                cc._propAttr('checked', false);
                cc.each(function () {
                    if (_isChecked($(this).val(), val)) {
                        $(this)._propAttr('checked', true);
                    }
                });
                return true;
            }
            return false;
        }

        function _isChecked(v, val) {
            if (v == String(val) || $.inArray(v, $.isArray(val) ? val : [val]) >= 0) {
                return true;
            } else {
                return false;
            }
        }

        function _loadBox(name, val) {
            var field = $(target).find('[textboxName="' + name + '"],[sliderName="' + name + '"]');
            if (field.length) {
                for (var i = 0; i < opts.fieldTypes.length; i++) {
                    var type = opts.fieldTypes[i];
                    var state = field.data(type);
                    if (state) {
                        if (state.options.multiple || state.options.range) {
                            field[type]('setValues', val);
                        } else {
                            field[type]('setValue', val);
                        }
                        return true;
                    }
                }
            }
            return false;
        }
    }

    /**
     * clear the form fields
     */
    function clear(target) {
        $('input,select,textarea', target).each(function () {
            var t = this.type, tag = this.tagName.toLowerCase();
            if (t == 'text' || t == 'hidden' || t == 'password' || tag == 'textarea') {
                this.value = '';
            } else if (t == 'file') {
                var file = $(this);
                if (!file.hasClass('textbox-value')) {
                    var newfile = file.clone().val('');
                    newfile.insertAfter(file);
                    if (file.data('validatebox')) {
                        file.validatebox('destroy');
                        newfile.validatebox();
                    } else {
                        file.remove();
                    }
                }
            } else if (t == 'checkbox' || t == 'radio') {
                this.checked = false;
            } else if (tag == 'select') {
                this.selectedIndex = -1;
            }

        });

        var form = $(target);
        var opts = $.data(target, 'form').options;
        for (var i = opts.fieldTypes.length - 1; i >= 0; i--) {
            var type = opts.fieldTypes[i];
            var field = form.find('.' + type + '-f');
            if (field.length && field[type]) {
                field[type]('clear');
            }
        }
        form.form('validate');
    }

    function reset(target) {
        target.reset();
        var form = $(target);
        var opts = $.data(target, 'form').options;
        for (var i = opts.fieldTypes.length - 1; i >= 0; i--) {
            var type = opts.fieldTypes[i];
            var field = form.find('.' + type + '-f');
            if (field.length && field[type]) {
                field[type]('reset');
            }
        }
        form.form('validate');
    }

    /**
     * set the form to make it can submit with ajax.
     */
    function setForm(target) {
        var options = $.data(target, 'form').options;
        $(target).unbind('.form');
        if (options.ajax) {
            $(target).bind('submit.form', function () {
                setTimeout(function () {
                    ajaxSubmit(target, options);
                }, 0);
                return false;
            });
        }
        setValidation(target, options.novalidate);
    }

    function initForm(target, options) {
        options = options || {};
        var state = $.data(target, 'form');
        if (state) {
            $.extend(state.options, options);
        } else {
            $.data(target, 'form', {
                options: $.extend({}, $.fn.form.defaults, $.fn.form.parseOptions(target), options)
            });
        }
    }

    function setValiate(target, options) {
        $(target).validate({
            errorElement: "span",
            errorClass: "help-block help-block-error",
            focusInvalid: !1,
            ignore: "",
            messages: options.validate ? options.validate.messages : "",
            rules: options.validate ? options.validate.rules : "",
            errorPlacement: function (e, r) {
                r.is(":checkbox") ? e.insertAfter(r.closest(".md-checkbox-list, .md-checkbox-inline, .checkbox-list, .checkbox-inline")) : r.is(":radio") ? e.insertAfter(r.closest(".md-radio-list, .md-radio-inline, .radio-list,.radio-inline")) : e.insertAfter(r)
            },
            highlight: function (e) {
                $(e).closest(".form-group").addClass("has-error")
            },
            unhighlight: function (e) {
                $(e).closest(".form-group").removeClass("has-error")
            },
            success: function (e) {
                e.closest(".form-group").removeClass("has-error");
            }
        });
    }

    function validate(target) {
        if ($.fn.validatebox) {
            var t = $(target);
            t.find('.validatebox-text:not(:disabled)').validatebox('validate');
            var invalidbox = t.find('.validatebox-invalid');
            invalidbox.filter(':not(:disabled):first').focus();
            return invalidbox.length == 0;
        }
        return true;
    }

    function setValidation(target, novalidate) {
        var opts = $.data(target, 'form').options;
        opts.novalidate = novalidate;
    }

    $.fn.form = function (options, param) {
        if (typeof options == 'string') {
            this.each(function () {
                initForm(this);
            });
            return $.fn.form.methods[options](this, param);
        }

        return this.each(function () {
            initForm(this, options);
            setForm(this);
            setValiate(this, options);
        });
    };

    $.fn.form.methods = {
        options: function (jq) {
            return $.data(jq[0], 'form').options;
        },
        submit: function (jq, options) {
            return jq.each(function () {
                ajaxSubmit(this, options);
            });
        },
        load: function (jq, data) {
            return jq.each(function () {
                load(this, data);
            });
        },
        clear: function (jq) {
            return jq.each(function () {
                clear(this);
            });
        },
        reset: function (jq) {
            return jq.each(function () {
                reset(this);
            });
        },
        validate: function (jq) {
            return validate(jq[0]);
        },
        disableValidation: function (jq) {
            return jq.each(function () {
                setValidation(this, true);
            });
        },
        enableValidation: function (jq) {
            return jq.each(function () {
                setValidation(this, false);
            });
        },
        resetValidation: function (jq) {
            return jq.each(function () {
                $(this).find('.validatebox-text:not(:disabled)').validatebox('resetValidation');
            });
        },
        resetDirty: function (jq) {
            return jq.each(function () {
                $(this).form('options').dirtyFields = [];
            });
        }
    };

    $.fn.form.parseOptions = function (target) {
        var t = $(target);
        return $.extend({}, {
            url: (t.attr('action') ? t.attr('action') : undefined)
        });
    };

    $.fn.form.defaults = {
        fieldTypes: ['combobox', 'combotree', 'combogrid', 'combotreegrid', 'datetimebox', 'datebox', 'combo',
            'datetimespinner', 'timespinner', 'numberspinner', 'spinner',
            'slider', 'searchbox', 'numberbox', 'passwordbox', 'filebox', 'textbox', 'switchbutton'],
        novalidate: false,
        ajax: true,
        iframe: true,
        dirty: false,
        dirtyFields: [],
        url: null,
        queryParams: {},
        multipart: false,
        contentType: null,
        headers: null,
        onSubmit: function (param) {
            $(this).find("input,select,textarea").each(function (index,e) {
                if(this.type !== 'file' && $(this).val()){
                    $(this).val($(this).val().trim());
                }
            });
            return $(this).valid();
        },
        onProgress: function (percent) {
        },
        success: function (data) {
        },
        error: function (data) {
        },
        onBeforeLoad: function (param) {
        },
        onLoadSuccess: function (data) {
        },
        onLoadError: function () {
        },
        onChange: function (target) {
        }
    };
})(jQuery);
